package common

import (
	"encoding/json"
	lru "github.com/hashicorp/golang-lru"
	"log"
	"math/rand"
	"net"
	"time"
)

const (
	KV_PAIR_INCR         = "renai_kv_pair_incr"
	KV_LIST_INSERT       = "renai_kv_list_insert_v2"
	KV_LIST_RANGE        = "renai_kv_list_range_v2"
	KV_QUEUE_ADD         = "renai_kv_queue_add_v2"
	KV_QUEUE_RANGE       = "renai_kv_queue_range_v2"
	KV_QUEUE_RANGE_SCORE = "renai_kv_queue_range_score_v2"
	KV_QUEUE_RANK        = "renai_kv_queue_rank"
	KV_QUEUE_INCR        = "renai_kv_queue_incr"
	KV_MAP_SET           = "renai_kv_map_set_v2"
	KV_MAP_GET           = "renai_kv_map_get_v2"
	KV_MAP_INCR          = "renai_kv_map_incr"
	MSG_CONSUME          = "renai_msg_consume"
	LOCK_LOCK            = "renai_lock_lock_v2"
	TEXT_SAVE            = "renai_text_save_v2"
	TEXT_DELETE          = "renai_text_delete_v2"
	TEXT_DROP            = "renai_text_drop"
	TEXT_SEARCH          = "renai_text_search"
	ID_GENERATE          = "renai_id_generate"

	DEFAULT   = "default"
	DELIMITER = "::"
)

type ValueResult struct {
	Lv int64
	Iv int
	Sv string
}

func String(object any) string {
	str, ok := object.(string)
	if ok {
		return str
	}
	bytes, err := json.Marshal(object)
	PanicErr(err)
	return string(bytes)
}

func Parse(str string, target any) {
	err := json.Unmarshal([]byte(str), target)
	PanicErr(err)
}

func LocalIp() string {
	conn, err := net.Dial("udp", "8.8.8.8:53")
	if err != nil {
		LogErr(err)
		return "127.0.0.1"
	}
	defer conn.Close()
	ipAddress := conn.LocalAddr().(*net.UDPAddr)
	return ipAddress.IP.String()
}

func Sleep(seconds int) {
	time.Sleep(time.Duration(seconds) * time.Second)
}

func SleepMS(ms int) {
	time.Sleep(time.Duration(ms) * time.Millisecond)
}

func Random(n int) int {
	rand.NewSource(time.Now().UnixNano())
	return rand.Intn(n)
}

func TimeFormat(pattern string, t time.Time) string {
	return t.Format(pattern)
}

func TimeParse(str string) time.Time {
	t, err := time.Parse("2006-01-02 15:04:05", str)
	PanicErr(err)
	return t
}

func PanicErr(err error) {
	if err != nil {
		panic(err)
	}
}

func LogErr(err error) bool {
	if err != nil {
		log.Println(err)
		return true
	}
	return false
}

func ChanGet(ch chan any, timeout int) any {
	select {
	case result := <-ch:
		return result
	case <-time.After(time.Duration(timeout) * time.Second):
		return nil
	}
}

type Tuple2 struct {
	V1 any
	V2 any
}

func NewTuple2(v1 any, v2 any) Tuple2 {
	return Tuple2{V1: v1, V2: v2}
}

func Cache(size int) *lru.Cache {
	cache, err := lru.New(size)
	PanicErr(err)
	return cache
}

func Min(num1 int, num2 int) int {
	if num1 < num2 {
		return num1
	}
	return num2
}

func ArrayMin(nums []int) int {
	if len(nums) == 0 {
		return 0
	}
	min := nums[0]
	for _, num := range nums {
		if num < min {
			min = num
		}
	}
	return min
}

func ArrayMax(nums []int) int {
	if len(nums) == 0 {
		return 0
	}
	max := nums[0]
	for _, num := range nums {
		if num > max {
			max = num
		}
	}
	return max
}

func ArrayMin64(nums []int64) int64 {
	if len(nums) == 0 {
		return 0
	}
	min := nums[0]
	for _, num := range nums {
		if num < min {
			min = num
		}
	}
	return min
}

func ArrayMax64(nums []int64) int64 {
	if len(nums) == 0 {
		return 0
	}
	max := nums[0]
	for _, num := range nums {
		if num > max {
			max = num
		}
	}
	return max
}
